/*
 * Yabumi, a 2d scrolling shoot-em-up game.
 * Copyright (C) 2003 Gemma Teruaki <terugen@yabumi.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 */

#include <math.h>
#include "../taskmanager.h"
#include "../util.h"
#include "../sprite.h"
#include "../video.h"
#include "hitcircle.h"
#include "explosion.h"
#include "homing_tail.h"
#include "homing.h"

extern _list_header *active_task_list_header, *expired_task_list_header;
extern _list_header hitcircle_list_header;
_list_header homing_list_header;

void Homing_Init()
{
  Create_list(&homing_list_header);
}

void Homing_Free()
{
  Free_list(&homing_list_header);
}

_Homing *Homing_Create(int x, int y, int dx, int dy, int angle)
{
  _list_item *list_item;
  list_item = (_list_item *)pmalloc(sizeof(_list_item));
  Add_item_last(&homing_list_header, list_item);
  _Homing *homing = &list_item->data.Homing;
  homing->root = list_item;

  homing->x = x;
  homing->y = y;
  homing->dx = dx;
  homing->dy = dy;
  homing->angle = angle;
  return homing;
}

task Homing_Add(_option *optv)
{
  _Homing *homing;
  _Hitcircle *hitcircle;
  homing = (_Homing *)optv->socket[0];
  hitcircle = (_Hitcircle *)optv->socket[1];

  Task_Add(Homing_Move, homing, hitcircle, INFINITY_COUNT);
}

task Homing_Move(_option *optv)
{
  _Homing *homing;
  _Hitcircle *hitcircle;
  homing = (_Homing *)optv->socket[0];
  hitcircle = (_Hitcircle *)optv->socket[1];

  if (optv->count == ONETIME_COUNT) {
    optv->count = KILL_COUNT;
    Task_Add(Homing_Kill, homing, NULL, ONETIME_COUNT);
    return;
  };

  if (optv->count <= -1 * HOMING_LIFETIME ) {
    optv->count = KILL_COUNT;
    Task_Add(Homing_Kill, homing, NULL, ONETIME_COUNT);
    return;
  };

  cap_angle(&homing->angle);
  homing->x += HOMING_SPEED * cos(homing->angle * RM_PI) + (homing->dx >> 8);
  homing->y += HOMING_SPEED * sin(homing->angle * RM_PI) + (homing->dy >> 8);
  
  int tangle;
  tangle = atan3(hitcircle->x - homing->x, hitcircle->y - homing->y) / RM_PI;
  if(ifclockwise(homing->angle, tangle)) {
    homing->angle -= HOMING_ROTATE_SPEED;
  } else {
    homing->angle += HOMING_ROTATE_SPEED;
  };

  Task_Add(Homing_Tail_Draw,
	   Homing_Tail_Create(homing->x, homing->y, homing->angle),
	   homing, HOMING_TAIL_TIME);
  
  /* status check start */
  if (distance(homing->x, homing->y, hitcircle->x, hitcircle->y) <= 
      hitcircle->radius + HOMING_COLLISION_DISTANCE) {
    /*HIT!*/
    hitcircle->was_hit = __hit_homing;
    Task_Add(Explosion_Draw,
	     Explosion_Create(homing->x, homing->y), NULL,
	     ONETIME_COUNT + 15);
    optv->count = KILL_COUNT;
    Task_Add(Homing_Kill, homing, NULL, ONETIME_COUNT);
    return;
  };
  /* status check end */
};

task Homing_Kill(_option *optv)
{
  _Homing *homing;
  homing = (_Homing *)optv->socket[0];

  int i;
  _list_item *list_item;
  _task_item *task_item;

  if (optv->count == ONETIME_COUNT) {
    list_item = active_task_list_header->next->next;
    while (list_item != active_task_list_header->prev) {
      task_item = &list_item->data.task_item;
      for (i = 0; i < MAX_SOCKET; i++) {
	if (task_item->option.socket[i] == homing) {
	  task_item->option.count = KILL_COUNT;
	};
      };
      list_item = list_item->next;
    };
    list_item = expired_task_list_header->next->next;
    while (list_item != expired_task_list_header->prev) {
      task_item = &list_item->data.task_item;
      for (i = 0; i < MAX_SOCKET; i++) {
	if (task_item->option.socket[i] == homing) {
	  task_item->option.count = KILL_COUNT;
	};
      };
      list_item = list_item->next;
    };
    Kill_item(&homing_list_header, (_list_item *)homing->root);
    pfree(homing->root);
  };
}

